package com.hisense.ovcloud.ps.service;

import com.hisense.ovcloud.commons.configs.base.BaseResponse;
import com.hisense.ovcloud.commons.configs.redis.RedisDao;
import com.hisense.ovcloud.ps.Constants;
import com.hisense.ovcloud.ps.dto.req.CertifyReq;
import com.hisense.ovcloud.ps.dto.req.VerifyReq;
import com.hisense.ovcloud.ps.dto.resp.CertifyResp;
import com.hisense.ovcloud.ps.dto.resp.OldVertifyResp;
import com.hisense.ovcloud.ps.dto.resp.VertifyResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.UUID;

@Service
@Slf4j
public class TokenServiceZip {

    private final RedisDao redisDao;
    @Value("${token.expireSeconds:800}")
    private int expireSeconds;
    @Value("${printRedisTime}")
    private boolean printRedisTime;

    public TokenServiceZip(RedisDao redisDao) {
        this.redisDao = redisDao;
    }

    public Mono<BaseResponse> certify(Mono<CertifyReq> req) {
        return req.flatMap(r -> deleteAndCreateToken(r.getWifiId(), UUID.randomUUID().toString().replaceAll("-", ""))
        );
    }

    //TODO error
    private Mono<BaseResponse> deleteAndCreateToken(String wifiId, String uuid) {
        final long start = System.currentTimeMillis();
        return Mono.zip(redisDao.get(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, wifiId))
                                .switchIfEmpty(Mono.just(Constants.REDIS_NULL_VALUE))
                                .zipWhen(oldToken -> redisDao.del(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, oldToken)), (o, v) -> true),
                        redisDao.set(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, wifiId), uuid, expireSeconds))
                .zipWhen(v -> redisDao.set(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, uuid), wifiId, expireSeconds), (o, v) -> v)
                .zipWhen(v -> {
                    if(printRedisTime){
                        log.info("certify redis consume: {} ms", System.currentTimeMillis()-start);
                    }
                    return Mono.just(BaseResponse.builder().code(Constants.RESULT_SUCCESS).data(CertifyResp.builder().token(uuid).build()).build());
                }, (o, v) -> v);
    }

    //null check
    public Mono<BaseResponse> verify(Mono<VerifyReq> req) {
        final long start = System.currentTimeMillis();
        return req.flatMap(r -> redisDao.get(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, r.getToken()))
                .switchIfEmpty(Mono.just(Constants.REDIS_NULL_VALUE))
                .zipWhen(wifiId -> Mono.just(VertifyResp.builder().build()), (wifiId, w) -> {
                    if(printRedisTime){
                        log.info("verify token {} redis get consume: {} ms", r.getToken(), System.currentTimeMillis()-start);
                    }

                    if(wifiId.equals(Constants.REDIS_NULL_VALUE)){
                        log.debug("wifiId {} not found for token {}", wifiId, r.getToken());
                        return BaseResponse.builder().code(Constants.RESULT_FAILED).data(VertifyResp.builder().wifiId("").build()).build();
                    }else{
                        log.debug("succeed to verify token {} for wifiId {}", r.getToken(), wifiId);
                        return BaseResponse.builder().code(Constants.RESULT_SUCCESS).data(VertifyResp.builder().wifiId(wifiId).build()).build();
                    }
                }));
    }

    public Mono<OldVertifyResp> vertify(Mono<VerifyReq> req) {
        final long start = System.currentTimeMillis();
        return req.flatMap(r -> redisDao.get(String.format("%s%s", Constants.AUTH_REDIS_PREFIX, r.getToken()))
                .switchIfEmpty(Mono.just(Constants.REDIS_NULL_VALUE))
                .zipWhen(wifiId -> Mono.just(OldVertifyResp.builder().build()), (wifiId, w) -> {
                    if(printRedisTime){
                        log.info("verify token {} redis get consume: {} ms", r.getToken(), System.currentTimeMillis()-start);
                    }

                    if(wifiId.equals(Constants.REDIS_NULL_VALUE)){
                        log.debug("wifiId {} not found for token {}", wifiId, r.getToken());
                        return OldVertifyResp.builder().wifiId("").code(Constants.RESULT_FAILED).build();
                    }else{
                        log.debug("succeed to verify token {} for wifiId {}", r.getToken(), wifiId);
                        return OldVertifyResp.builder().wifiId(wifiId).code(Constants.RESULT_SUCCESS).build();
                    }
                }));
    }
}
